#ifndef __WIZ_BNF_RULE_HPP__SHANHAOBO_19800429__
#define __WIZ_BNF_RULE_HPP__SHANHAOBO_19800429__

#include "../../DataType/SmartPtr/WizDataTypeScopedPtr.hpp"

#include "./WizBNFParserAbstract.hpp"
#include "../WizBNFContext.hpp"

namespace Wiz
{
    namespace BNF
    {
        namespace Rule
        {
            namespace Base
            {
                template
                <
                    typename DerivedT,
                    typename EmbeddedT,
                    typename ScannerT,
                    typename ContextT,
                    typename TagT
                >
                class Type;
            } /// end of namespace Base

            class Access
            {
                template
                <
                    typename DerivedT,
                    typename EmbeddedT,
                    typename ScannerT,
                    typename ContextT,
                    typename TagT
                >
                friend class ::Wiz::BNF::Rule::Base::Type;

                template <typename RuleT>
                static typename RuleT::tAbstractParser*
                Get(RuleT const& Rl)
                {
                    return Rl.Get();
                }
            };
            namespace Base
            {
                template<class DerivedT, class EmbeddedT, class ScannerT, class ContextT, class TagT>
                class Type :
                    public ::Wiz::BNF::Parser::Type<DerivedT>,
                    public ContextT::tSuper,
                    public ::Wiz::BNF::Context::AUX::Type<ContextT, DerivedT>,
                    public TagT
                {
                public:
                    typedef ScannerT                                tScanner;
                    typedef ContextT                                tContext;
                    typedef TagT                                    tTag;

                    typedef EmbeddedT                               tEmbedded;
                    typedef typename tContext::tContextLinker       tContextLinker;
                    typedef typename tContextLinker::tAttribute     tAttribute;

                    template <typename ScannerT2>
                    struct Result
                    {
                        typedef typename ::Wiz::BNF::Match::Result<ScannerT2, tAttribute>::tType tType;
                    };

                    template <typename ScannerT2>
                    typename ::Wiz::BNF::Parser::Result<DerivedT, ScannerT2>::tType
                    ParseImpl(ScannerT2 const& Scan) const
                    {
                        typedef ::Wiz::BNF::Scanner::Linker::Type<ScannerT2>            tScannerLinker;
                        typedef ::Wiz::BNF::Parser::Result<DerivedT, ScannerT2>::tType   tResult;

                        tScannerLinker ScanWrap(Scan);
                        tContextLinker ContextWrap(*this); 
                        ContextWrap.PreParse(*this, ScanWrap);
                        tResult Hit = ParseMain(Scan);
                        return ContextWrap.PostParse(Hit, *this, ScanWrap);
                    }

                    template <typename ScannerT2>
                    typename ::Wiz::BNF::Parser::Result<DerivedT, ScannerT2>::tType
                    ParseMain(ScannerT2 const& Scan) const
                    {
                        typedef ::Wiz::BNF::Parser::Result<DerivedT, ScannerT2>::tType  tResult;
                        tResult                                                         Hit;

                        DerivedT const* DerivedThis = static_cast<DerivedT const*>(this);

                        if (::Wiz::BNF::Rule::Access::Get(*DerivedThis))
                        {
                            ScannerT2::tIterator Start = Scan.m_Curr;
                            Hit = ::Wiz::BNF::Rule::Access::Get(*DerivedThis)->DoParse(Scan);
                            Scan.GroupMatch(Hit, this->ID(), Start, Scan.m_Curr);
                        }
                        else
                        {
                            Hit = Scan.NoMatch();
                        }
                        return Hit;
                    }
                };
            } /// end of namespace Base

            template <
                typename ScannerT = ::Wiz::BNF::Scanner::Type<>,
                typename ContextT = ::Wiz::BNF::Context::Type<>,
                typename TagT = ::Wiz::BNF::Tag::Address::Type
            >
            class Type : public ::Wiz::BNF::Rule::Base::Type<Type<ScannerT, ContextT, TagT>, Type<ScannerT, ContextT, TagT> const& , ScannerT, ContextT, TagT>
            {
            public:
                typedef Type<ScannerT, ContextT, TagT>                                                  tThis;
                typedef ::Wiz::BNF::Rule::Base::Type<tThis, tThis const&, ScannerT, ContextT, TagT>     tSuper;

                typedef typename tSuper::tScanner                                                       tScanner;
                typedef typename tSuper::tAttribute                                                     tAttribute;
                typedef ::Wiz::BNF::Parser::Abstract::Type<tScanner, tAttribute>                        tAbstractParser;

                Type() : m_Ptr() {}
                ~Type() {}

                Type(Type const& r) : m_Ptr(new ::Wiz::BNF::Parser::Concrete::Type<Type, tScanner, tAttribute>(r))
                {}

                template <typename ParserT>
                Type(ParserT const& Prs) : m_Ptr(new ::Wiz::BNF::Parser::Concrete::Type<ParserT, tScanner, tAttribute>(Prs))
                {}

                template <typename ParserT>
                Type& operator=(ParserT const& Prs)
                {
                    m_Ptr.Reset(new ::Wiz::BNF::Parser::Concrete::Type<ParserT, tScanner, tAttribute>(Prs));
                    return *this;
                }

                Type& operator=(Type const& r)
                {
                    m_Ptr.Reset(new ::Wiz::BNF::Parser::Concrete::Type<Type, tScanner, tAttribute>(r));
                    return *this;
                }

                tThis Copy() const
                {
                    return Type<ScannerT, ContextT, TagT>(m_Ptr.Get() ? m_Ptr->Clone() : WIZ_NULLPTR);
                }

            private:
                friend class Access;

                tAbstractParser* Get() const
                {
                    return m_Ptr.Get();
                }

                Type(tAbstractParser* m_Ptr) : m_Ptr(m_Ptr) {}

                Type(tAbstractParser const* m_Ptr) : m_Ptr(m_Ptr) {}

                ::Wiz::ScopedPtr::Type<tAbstractParser> m_Ptr;
            };
        } /// end of namespace Rule
    } /// end of namespace BNF
} /// end of namespace Wiz

#endif /*__WIZ_BNF_RULE_HPP__SHANHAOBO_19800429__*/
